package io.plus.utils.thread.lock_capable_task;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

@Data
@Slf4j
public abstract class AbstractTask implements Runnable {
    public Executor executor;
    /**
     * 是否【已经】提交到线程池了
     */
    public boolean executed = false;
    //
    protected ReentrantLock runnableLock = new ReentrantLock();
    private boolean isCanceled = false;

    protected AbstractTask(Executor executor) {
        this.executor = executor;
    }

    //
    public abstract boolean isNeededExecute();

    /**
     * 把本任务对象提交到线程池去执行
     */
    public void execute() {
        executor.execute(this);
    }

    //
    @Override
    public final void run() {
        //任务已经被取消
        if (isCanceled()) {
            return;
        }
        boolean tryLock = false;
        try {
            tryLock = runnableLock.tryLock(1L, TimeUnit.SECONDS);
        } catch (InterruptedException e1) {
            log.error(e1.toString(), e1);
        }
        if (tryLock) {
            try {
                int loopCount = 0;
                runTask();
                while (isNeededExecute() && loopCount++ < 100) {
                    runTask();
                }
            } catch (Throwable e) {
                log.error(e.toString(), e);
            } finally {
                executed = false;
                runnableLock.unlock();
            }
        } else {
            executed = false;
        }

        //下面这段代码一定要在unlock()后面，别弄错了 ^_^
        if (isNeededExecute()) {
            execute();
        }

    }

    public abstract void runTask();

}
